package org.os.framework.context.config;

import java.util.Calendar;
import java.util.HashMap;
import java.util.Map;
import java.util.Optional;

import org.os.framework.context.model.HttpException;
import org.springframework.boot.context.properties.ConfigurationProperties;
import org.springframework.context.annotation.Configuration;
import com.alibaba.fastjson.JSON;
import com.auth0.jwt.JWTVerifier;
import com.auth0.jwt.algorithms.Algorithm;
import com.auth0.jwt.interfaces.DecodedJWT;

import lombok.Data;
import lombok.extern.slf4j.Slf4j;

/**
 * JWT
 * @author
 */
@Slf4j
@Data
@ConfigurationProperties(prefix = "spring.json-web-token")
@Configuration
public class JsonWebToken {

    /**
     * HMAC256密钥
     */
    private String secret = "~!@#$%^&*()_+";

    /**
     * token有效期
     */
    private Integer expires = 7200;

    /**
     * 算法
     */
    private String algorithm = "SHA256";

    /**
     * 类型
     */
    private String type = "JWT";

    /**
     * 头部信息
     * 
     * @return
     */
    private Map<String, Object> head() {
        Map<String, Object> header = new HashMap<>(16);
        header.put("alg", algorithm);
        header.put("type", type);
        return header;
    }

    /**
     * 生成
     */
    public String generate(Object obj) {
        return generate(obj, expires);
    }

    /**
     * 生成
     */
    public String generate(Object obj, Integer timeout) {
        if (null == obj) {
            obj = new Object();
        }
        if (obj instanceof String) {
            throw new HttpException("Not Support", "不支持string类型");
        }
        String str = JSON.toJSONString(obj);
        Calendar tokenTimeout = Calendar.getInstance();
        tokenTimeout.add(Calendar.SECOND, timeout);
        com.auth0.jwt.JWTCreator.Builder builder = com.auth0.jwt.JWT.create()
                .withHeader(head())
                .withSubject(str)
                .withExpiresAt(tokenTimeout.getTime());
        return builder.sign(Algorithm.HMAC256(secret));
    }

    /**
     * 解析
     */
    public Optional<Object> parse(String token) {
        return parse(token, Object.class);
    }

    /**
     * 解析
     */
    public <T> Optional<T> parse(String token, Class<T> convert) {
        if (null == token || "".equals(token)) {
            return Optional.empty();
        }
        try {
            JWTVerifier verifier = com.auth0.jwt.JWT.require(Algorithm.HMAC256(secret)).build();
            DecodedJWT jwt = verifier.verify(token);
            String str = jwt.getSubject();
            T entity = JSON.parseObject(str, convert);
            return Optional.ofNullable(entity);
        } catch (Exception e) {
            log.error("JWT解析失败 =>\n", e);
        }
        return Optional.empty();
    }

}
